﻿//#define USE_DUNGEONBUDDY_DLL

using System;
using System.Collections.Generic;
using System.Linq;
using CommonBehaviors.Actions;
using Styx;
using Styx.Common.Helpers;
using Styx.CommonBot;
using Styx.CommonBot.Frames;
using Styx.Helpers;
using Styx.Patchables;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals.World;
using Action = Styx.TreeSharp.Action;
#if USE_DUNGEONBUDDY_DLL
using Bots.DungeonBuddyDll;
using Bots.DungeonBuddyDll.Profiles;
using Bots.DungeonBuddyDll.Attributes;
using Bots.DungeonBuddyDll.Helpers;

namespace Bots.DungeonBuddyDll.Dungeon_Scripts.Mists_of_Pandaria
#else
    using Bots.DungeonBuddy.Profiles;
    using Bots.DungeonBuddy.Attributes;
    using Bots.DungeonBuddy.Helpers;
namespace Bots.DungeonBuddy.Dungeon_Scripts.Mists_of_Pandaria
#endif
{
    public class Siege_OfNiuzaoTempleHeroic : Dungeon
    {
        #region Overrides of Dungeon

        public override uint DungeonId
        {
            get { return 554; }
        }

        public override WoWPoint Entrance
        {
            get { return new WoWPoint(1441.83, 5089.116, 139.3459); }
        }

        public override void RemoveTargetsFilter(List<WoWObject> units)
        {
            units.RemoveAll(
                ret =>
                    {
                        var unit = ret.ToUnit();
                        if (unit != null)
                        {
                            if (_commanderVojakAdds.Contains(unit.Entry) && Me.Z < 180)
                                return true;
                            if (unit.Entry == AmberWingId || unit.Entry == SikthikFlyerId)
                                return true;
                            if (unit.Entry == SikthikDemolisherId && Me.IsTank())
                                return true;
                            if (unit.Entry == CommanderVojakId && unit.ToUnit().HasAura("Thousand Blades") && Me.IsMelee())
                                return true;
                        }
                        return false;
                    });
        }

        public override void IncludeTargetsFilter(List<WoWObject> incomingunits, HashSet<WoWObject> outgoingunits)
        {
            foreach (var obj in incomingunits)
            {
                if (obj is WoWGameObject && obj.Entry == HardenResin)
                {
                    outgoingunits.Add(obj);
                }
                var unit = obj as WoWUnit;
                if (unit != null)
                {
                    if (unit.Entry == SikthikDemolisherId && unit.Distance <= 35 && unit.InLineOfSpellSight && Me.IsRange())
                        outgoingunits.Add(unit);

                    if (_commanderVojakAdds.Contains(unit.Entry) && unit.Attackable && unit.Distance < 40 && (Me.IsRange() && Me.IsDps() || Me.IsTank() && unit.Z > 150) &&
                        unit.InLineOfSpellSight)
                        outgoingunits.Add(unit);
                }
            }
        }

        public override void WeighTargetsFilter(List<Targeting.TargetPriority> units)
        {
            foreach (var priority in units)
            {
                var unit = priority.Object as WoWUnit;
                if (unit != null)
                {
                    if (unit.Entry == SikthikDemolisherId)
                        priority.Score += 5500;

                    if (unit.Entry == SikthikWarriorId && Me.IsDps())
                        priority.Score = +5000;
                }
            }
        }

        #endregion

        private const uint SapPuddleId = 61965;
        private const uint SapPuddle2Id = 61579;
        private const uint SapPuddleBossId = 61613;
        private const uint VizierJinbakId = 61567;
        private const uint AmberWingId = 61699;
        private const int DetonateId = 120001;
        private const uint CommanderVojakId = 61634;
        private const uint SikthikDemolisherId = 61670;
        private const uint HardenResin = 213174;
        private const uint SikthikWarriorId = 61701;
        private const uint SikthikSwarmerId = 63106;
        private const uint SikthikFlyerId = 62091;

        private readonly uint[] _commanderVojakAdds = new[] {CommanderVojakId, SikthikDemolisherId, SikthikWarriorId, SikthikSwarmerId};

        private LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        [EncounterHandler(0)]
        public Composite RootBehavior()
        {
            return
                new PrioritySelector(
                    ScriptHelpers.CreateRunAwayFromBad(ctx => !Me.IsMoving, 4f, u => u.Entry == SapPuddleId && u.ToUnit().HasAura("Sap Puddle") && u.ZDiff < 6));
        }

        [EncounterHandler(64517, "Shado-Master Chum Kiu", Mode = CallBehaviorMode.Proximity)]
        public Composite ShadoMasterChumKiuEncounter()
        {
            return new PrioritySelector(new Decorator<WoWUnit>(unit => unit.QuestGiverStatus == QuestGiverStatus.Available, ScriptHelpers.CreatePickupQuest(64517)));
        }

        [EncounterHandler(61567, "Vizier Jin'bak", Mode = CallBehaviorMode.Proximity, BossRange = 100)]
        public Composite VizierJinbakEncounter()
        {
            WoWUnit boss = null;
            WoWUnit puddle = null;

            return new PrioritySelector(
                ctx =>
                    {
                        puddle = ObjectManager.GetObjectsOfType<WoWUnit>().FirstOrDefault(u => u.Entry == SapPuddleBossId);
                        return boss = ctx as WoWUnit;
                    },
                ScriptHelpers.CreateRunAwayFromBad(
                    ctx => Me.HasAura("Sap Residue") || boss != null && boss.IsValid && boss.CastingSpellId == DetonateId, obj => 5*(obj.Scale*4/5 + 1), SapPuddleBossId),
                new Decorator(ctx => !boss.CanSelect, ScriptHelpers.CreateClearArea(() => boss.Location, 100, u => u.Z <= 175)),
                new Decorator(
                    ctx => boss.Combat,
                    new PrioritySelector(
                        new Decorator(
                            ctx => !Me.IsHealer && !Me.HasAura("Sap Residue") && boss.CastingSpellId != DetonateId && puddle.Distance > 5,
                            new Action(ctx => Navigator.MoveTo(puddle.Location))))));
        }

        [ObjectHandler(213174, "Hardened Resin", ObjectRange = 8)]
        public Composite HardenedResinHandler()
        {
            WoWGameObject resin = null;
            return new PrioritySelector(
                ctx => resin = ctx as WoWGameObject,
                new Decorator<WoWGameObject>(
                    obj => !Me.Combat && obj.State == WoWGameObjectState.Ready,
                    new PrioritySelector(new Decorator(ctx => Me.IsMoving, new Action(ctx => WoWMovement.MoveStop())), new Action(ctx => resin.Interact()))));
        }

        [EncounterHandler(61634, "Commander Vo'jak", Mode = CallBehaviorMode.Proximity, BossRange = 8000)]
        public Composite CommanderVojakEncounter()
        {
            WoWUnit boss = null;
            WoWUnit yang = null;
            WoWUnit keg = null;

            var platformCenterLoc = new WoWPoint(1521.815, 5294.988, 184.6694);
            var barrelThrowStart = new WoWPoint(1505.429, 5329.327, 161.2022);
            var barrelThrowEnd = new WoWPoint(1561.556, 5333.001, 161.2266);
            var throwStart = new WoWPoint(1492.644, 5312.728, 184.6486);
            var throwEnd = new WoWPoint(1554.358, 5317.484, 184.6486);
            var incAddsLoc = new WoWPoint(1510.148, 5372.519, 139.0868);

            WoWPoint kegThrowFromLoc = WoWPoint.Zero;
            WoWPoint kegThrowFromTo = WoWPoint.Zero;
            WoWUnit[] incAdds = null;
#if BW_77 
                        ScriptHelpers.CreateRunAwayFromBad(
              ctx => true,
                () => platformCenterLoc,
                25,
                15,
                u => u.Entry == CommanderVojakId && (u.ToUnit().HasAura("Thousand Blades") || u.ToUnit().HasAura("Dashing Strike")));
            ScriptHelpers.CreateRunAwayFromBad(ctx => true, 8f, SapPuddle2Id);
            ScriptHelpers.CreateRunAwayFromBad(ctx => Me.IsHealer() || Me.IsDps() && Me.IsMelee(), 20f, SikthikDemolisherId);
#else
            AddAvoidObject(
                ctx => true,
                () => platformCenterLoc,
                25,
                15,
                u => u.Entry == CommanderVojakId && (u.ToUnit().HasAura("Thousand Blades") || u.ToUnit().HasAura("Dashing Strike")));
            AddAvoidObject(ctx => true, 8f, SapPuddle2Id);
            AddAvoidObject(ctx => Me.IsHealer() || Me.IsDps() && Me.IsMelee(), 20f, SikthikDemolisherId);
#endif
            return new PrioritySelector(
                ctx =>
                    {
                        yang = ObjectManager.GetObjectsOfType<WoWUnit>().FirstOrDefault(u => u.Entry == 61620);
                        incAdds = ScriptHelpers.GetUnfriendlyNpsAtLocation(() => incAddsLoc, 90, u => u.Z < 183).ToArray();

                        keg =
                            ObjectManager.GetObjectsOfType<WoWUnit>().Where(
                                u =>
                                u.Entry == 61817 && u.HasAura("Mantid Barrel Active") && u.TransportGuid == 0 &&
                                Me.RaidMembers.OrderBy(r => r.Location.DistanceSqr(u.Location)).FirstOrDefault() == Me).OrderBy(u => u.DistanceSqr).FirstOrDefault();
                        boss = (WoWUnit) ctx;

                        return boss;
                    },
                // start the event
                new Decorator(ctx => Me.IsTank() && yang != null && yang.CanGossip && Targeting.Instance.IsEmpty(), ScriptHelpers.CreateTalkToNpc(() => yang)),
                // cast ranged ability on the demolishers if melee.
                new Decorator(
                    ctx => Me.IsMelee() && !Targeting.Instance.IsEmpty() && Targeting.Instance.FirstUnit.Entry == SikthikDemolisherId, ScriptHelpers.CreateCastRangedAbility()),
                // should I pick up a keg of tar?
                new Decorator(
                    ctx =>
                    keg != null &&
                    (Targeting.Instance.IsEmpty() || (Me.IsDps() && Me.IsRange() && incAdds.Any()) || boss.Z > 182 && !boss.HasAura("Caustic Tar") && Me.IsDps()),
                    new PrioritySelector(
                        new ActionSetActivity("Throwing Kegs"),
                        new Decorator(
                            // dont have a keg? go pick one up.
                            ctx => !Me.HasAura("Carrying Caustic Tar"),
                            new PrioritySelector(
                                new Decorator(ctx => !keg.WithinInteractRange, new Action(ctx => Navigator.MoveTo(keg.Location))),
                                new Decorator(
                                    ctx => keg.WithinInteractRange,
                                    new Sequence(new Action(ctx => Navigator.NavigationProvider.StuckHandler.Reset()), new Action(ctx => keg.Interact()))))))),
                new Decorator(
                    ctx => Me.HasAura("Carrying Caustic Tar"),
                    new PrioritySelector(
                        ctx =>
                            {
                                kegThrowFromTo = boss.Z > 182 ? boss.Location : Me.Location.GetNearestPointOnSegment(barrelThrowStart, barrelThrowEnd);
                                return
                                    kegThrowFromLoc =
                                    boss.Z > 182
                                        ? Me.Location.GetNearestPointOnSegment(boss.Location, WoWMathHelper.CalculatePointFrom(Me.Location, boss.Location, 25))
                                        : Me.Location.GetNearestPointOnSegment(throwStart, throwEnd);
                            },
                        new Decorator(ctx => kegThrowFromLoc.Distance(Me.Location) > 4f, new Action(ctx => PrecisionMoveto(kegThrowFromLoc))),
                        new Decorator(
                            ctx => kegThrowFromLoc.Distance(Me.Location) <= 4f,
                            new Sequence(
                                new Action(ctx => Navigator.NavigationProvider.StuckHandler.Reset()), new Action(ctx => SpellManager.ClickRemoteLocation(kegThrowFromTo)))))),
                // range dps move to edge to dps stuff coming up stairs
                new Decorator(
                    ctx =>
                    (Me.IsRange() || Me.IsMelee() && Targeting.Instance.IsEmpty()) && incAdds.Any(u => u.Entry == SikthikDemolisherId) && Me.IsDps() && boss.Z < 182 &&
                    Me.Location.Distance(Me.Location.GetNearestPointOnSegment(throwStart, throwEnd)) > 3,
                    new Action(ctx => PrecisionMoveto(Me.Location.GetNearestPointOnSegment(throwStart, throwEnd)))),
                new Decorator(
                    ctx => Me.IsTank() && Targeting.Instance.TargetList.All(u => u.CurrentTargetGuid == Me.Guid),
                    ScriptHelpers.CreateTankUnitAtLocation(() => platformCenterLoc, 5)),
                // stay on playform.
                new Decorator(ctx => Me.IsTank() && Me.Location.DistanceSqr(platformCenterLoc) > 30*30, new Action(ctx => Navigator.MoveTo(platformCenterLoc))),
                new Decorator(ctx => !Me.IsHealer() && Targeting.Instance.IsEmpty(), new ActionAlwaysSucceed()),
                new Decorator(ctx => Me.IsTank() && Targeting.Instance.IsEmpty(), new ActionAlwaysSucceed()));
        }

        private RunStatus PrecisionMoveto(WoWPoint destination)
        {
            var myLoc = Me.Location;
            if (myLoc.Distance(destination) > 10)
            {
                var moveResult = Navigator.MoveTo(destination);
                if (moveResult == MoveResult.PathGenerationFailed || moveResult == MoveResult.Failed)
                    return RunStatus.Failure;
            }
            else Navigator.PlayerMover.MoveTowards(destination);
            return RunStatus.Success;
        }
    }
}